3D Graphics Programming with QuickDraw 3D 1.5.4
Previous | QD3D Book | Overview | Chapter Contents | Next |
QuickDraw 3D allows you to define custom attribute types so that you can attach to a vertex (or face, or geometric object, or group, or view) types of data different from those associated with the basic attribute types defined by QuickDraw 3D. Once you have defined and registered your custom attribute type, you manipulate attributes of that type exactly as you manipulate the standard QuickDraw 3D attributes. For example, you add a custom attribute to an attribute set by calling Q3AttributeSet_Add , and you retrieve the data associated with a custom attribute by calling Q3AttributeSet_Get .
To define a custom attribute type, you first define the internal structure of the data associated with your custom attribute type. Then you must write an attribute metahandler to define a set of attribute-handling methods. QuickDraw 3D calls those methods at certain times to handle operations on attribute sets that contain your custom attribute. For example, when you call Q3Triangle_Write to write a triangle to a file, QuickDraw 3D might need to call your attribute's handler to write your custom attribute data to the file.
Suppose that you want to define a custom attribute that contains data about temperature over time. You might use the MyTemperatureData structure, defined like this:
typedef struct MyTemperatureData {
unsigned long startTime; /*starting time*/
unsigned long nTemps; /*no. temps in array*/
float *temperatures; /*array of temps*/
} MyTemperatureData;
Your attribute metahandler is an application-defined function that returns the addresses of the methods associated with the custom attribute type. A metahandler can define some or all of the methods indicated by these constants:
kQ3MethodTypeObjectDelete
kQ3MethodTypeObjectReadData
kQ3MethodTypeObjectTraverse
kQ3MethodTypeObjectWrite
kQ3MethodTypeElementCopyAdd
kQ3MethodTypeElementDelete
kQ3MethodTypeElementCopyDuplicate
kQ3MethodTypeElementCopyGet
kQ3MethodTypeElementCopyReplace
kQ3MethodTypeAttributeInterpolate
kQ3MethodTypeAttributeCopyInherit
kQ3MethodTypeAttributeInherit
Listing 10 defines a simple attribute metahandler. See "Defining an Object Metahandler" for a more complete description of metahandlers.
Listing 10 Reporting custom attribute methods
TQ3FunctionPointer MyTemperatureDataMetaHandler (TQ3MethodType methodType)
{
switch (methodType) {
case kQ3MethodTypeElementDelete:
return (TQ3FunctionPointer) MyTemperatureDataDispose;
case kQ3MethodTypeElementCopyReplace:
return (TQ3FunctionPointer) MyTemperatureDataCopyReplace;
case kQ3MethodTypeAttributeCopyInherit:
return (TQ3FunctionPointer) kQ3True;
case kQ3MethodTypeAttributeInherit:
return (TQ3FunctionPointer) kQ3True;
default:
return (NULL);
}
}
The MyTemperatureDataMetaHandler metahandler simply returns the appropriate function address, or NULL if the metahandler does not implement a particular method type. All the method types listed above are optional. (In fact, you don't need to specify a metahandler at all if you want QuickDraw 3D to use its default methods to handle your custom attribute type.)
The metahandler in Listing 10 installs the MyTemperatureDataDispose function as the custom attribute's dispose method, which QuickDraw 3D calls whenever you clear your custom attribute or replace an existing one. A dispose method is passed a pointer to the data associated with an attribute. Your dispose method should deallocate any storage you allocated, as shown in Listing 11 .
Listing 11 Disposing of a custom attribute's data
TQ3Status MyTemperatureDataDispose (MyTemperatureData *tmpData)
{
if (tData->temperatures != NULL) {
free(tmpData->temperatures);
tData->temperatures = NULL;
}
return kQ3Success;
}
If you do not define a dispose method, QuickDraw 3D automatically disposes of the block of data allocated when a custom attribute was added to an attribute set. If the data associated with a custom attribute is always of a fixed size and does not contain any pointers to other data that needs to be disposed of, you do not need to define a dispose or copy method.
The metahandler in Listing 10 installs the MyTemperatureDataCopyReplace function as the custom attribute's copy method. A copy method is passed two pointers, specifying the source and target addresses of the data to copy. Listing 12 shows a simple copy method.
Listing 12 Copying a custom attribute's data
TQ3Status MyTemperatureDataCopyReplace
(const MyTemperatureData *src, MyTemperatureData *dst)
{
float *temp;
if (dst->nTemps != src->nTemps) {
temp = realloc(dst->temperatures, nTemps * sizeof(float));
if (temp == NULL)
return (kQ3Failure);
}
dst->startTime = src->startTime;
dst->nTemps = src->nTemps;
dst->temperatures = temp;
memcpy(temp, dst->temperatures, dst->nTemps * sizeof(float));
return (kQ3Success);
}
If you do not define a copy method, QuickDraw 3D automatically copies the block of data using a default memory copy method.
The inherit method simply requests a Boolean value that indicates whether you want your custom attribute to be inherited down the class hierarchy. You should return kQ3True if you want your attribute to be inherited or kQ3False if not.
Before you can use a custom attribute type, you need to register your attribute metahandler with QuickDraw 3D by calling the Q3AttributeClass_Register function. You might execute the MyStartUpQuickDraw3D function defined in Listing 13 at application startup time.
Listing 13 Initializing QuickDraw 3D and registering a custom attribute type
TQ3AttributeType gAttributeType_Temperature;
void MyStartUpQuickDraw3D (void)
{
TQ3ObjectClass myAttrib;
if (Q3Initialize() == kQ3Failure) /*initialize QuickDraw 3D*/
MyFailRoutine();
/*register attribute type*/
myAttrib = Q3AttributeClass_Register(
gAttributeTypeTemperature,
"MyCompany:SurfWorks:Temperature",
sizeof(MyTemperatureData),
MyTemperatureData_MetaHandler);
if (myAttrib == kQ3ObjectTypeInvalid)
MyFailRoutine();
}
Previous | QD3D Book | Overview | Chapter Contents | Next |